﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using eTerm.MsSql.DbProvider;
using eTerm.Platform.Business;
using System.Threading;
using eTerm.PlugIn.DETRPlugIn;
using System.Collections;
using eTerm.PlugIn.NCore;
using System.Reflection;
using System.Xml.Linq;

using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System.Text.RegularExpressions;
using NPOI.HSSF.Util;

namespace eTerm.DETR.StandAloneVersion
{
    public partial class frmExecute : Form
    {

        private AutoDETRPlugIn PlugIn = new AutoDETRPlugIn();
        public frmExecute()
        {
            InitializeComponent();
            this.Load += (o, e) => {
                string connectionString = string.Format("Data Source={0};Version=3;New=False;Connection Timeout=3;", @"Excel.db");
                Context.Instance.DbProvider = new SqlDbProvider(connectionString, @"System.Data.SQLite");


                PlugIn.OnException += (p, x) =>
                {
                    AppendString(string.Format(@"执行 {0}  异常：
    {1}", x.PlugIn.PlugInName,x.Notify));
                };

                PlugIn.OnExecuted += (p, x) =>
                {
                    AppendString(x.Notify);
                };

                PlugIn.OnExecuting += (p, x) =>
                {
                    AppendString(x.Notify);
                };

                PlugIn.OnFrequency += (p, x) => { 
                        
                };

                PlugIn.OnNotify += (p, x) =>
                {
                    AppendString(string.Format(@" {0} 
    {1}", x.PlugIn.PlugInName, x.Notify));
                    if (x.NotifyType == EventType.INSTRUCT) {
                        RemoveTicketNo(new PnrDetr() { TicketNo = x.BusinessNo  });
                        RenderLvResult(x.BusinessNo);
                    }
                };
            };
        }

        #region UI日志


        private delegate void AppendStringBack(string text);

        private void AppendString(string text)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new AppendStringBack(AppendString), text);
                return;
            }
            try
            {
                //if (notifyIcon1.Visible) return;
                if (tbLog.Lines.Length > 500)
                    tbLog.Text = string.Empty;

                tbLog.AppendText(text);
                tbLog.AppendText(@"
");
                tbLog.SelectionStart = tbLog.TextLength;
                tbLog.ScrollToCaret();
            }
            catch { }
        }

        #endregion


        private void btnImport_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK) {
                lsvTicketNo.Items.Clear();
                FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open);
                {
                    ThreadStart starter = delegate { ExecuteFile(fs); };
                    new Thread(starter).Start();
                }
            }
        }


        private void RenderTicketNo(PnrDetr model) {
            if (this.InvokeRequired) {
                //RenderHandler handler = new RenderHandler(RenderTicketNo);
                //handler.BeginInvoke(
                this.BeginInvoke(new RenderHandler(RenderTicketNo), model);
                return;
            } else {
                this.lsvTicketNo.Items.Add(new ListViewItem(new string[] { 
                    model.Id.ToString(),
                    model.TicketNo 
                }) { Tag = model });
            }
        }

        private void RemoveTicketNo(PnrDetr item) {
            if (this.InvokeRequired)
            {
                //RenderHandler handler = new RenderHandler(RenderTicketNo);
                //handler.BeginInvoke(
                this.BeginInvoke(new RemoveListViewItemHandler(RemoveTicketNo), item);
                return;
            }
            else
            {
                //this.lsvTicketNo.Items.Remove(item);
                this.lsvTicketNo.Items.Cast<ListViewItem>().Where(l => (l.Tag as PnrDetr).TicketNo == item.TicketNo).ToList().ForEach(l => { this.lsvTicketNo.Items.Remove(l); });
                RenderProgress(null, toolProgress.Maximum - lsvTicketNo.Items.Count);
            }
        }

        private delegate void RemoveListViewItemHandler(PnrDetr item);

        private delegate void RenderHandler(PnrDetr model);

        private delegate void RenderStatusHandler(ToolStripItem item, string text,bool? enable);

        private delegate void RenderProgressHandler(int? MaxValue, int? CurrentValue);

        private delegate void RenderLvResultHandler(string TicketNo);

        private void RenderLvResult(string TicketNo) { 
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new RenderLvResultHandler(RenderLvResult), TicketNo);
                return;
            }
            else
            {
                var sql = PnrDetr.All().Where(l => l.TicketNo == TicketNo).OrderByDescending(l => l.ProcessDate)
                        .Join(SysUser.All(), l => l.UserId, r => r.UserId, (l, r) => new { r.CompanyCode, r.DisplayName, r.Email, l.StatusId, l.TicketNo, l.TicketDate, l.Id, l.ProcessDate, r.UserId })
                        .Join(SysCompany.All(), l => l.CompanyCode, r => r.CompanyCode, (l, r) => new { l.CompanyCode, l.DisplayName, l.Email, l.Id, l.StatusId, l.TicketDate, l.TicketNo, l.ProcessDate, l.UserId, r.CompayName })
                        .SelectMany(l => PnrSegment.All().GroupBy(g => g.TicketNoId, (Key, Items) => new { Key, FlightNos = Items.Select(y => string.Format("{0}({1}-{2})", y.FlightNo, y.Departure, y.Arrival)) }).Where(n => n.Key == l.Id).DefaultIfEmpty(), (l, r) => new { l.CompanyCode, l.CompayName, l.DisplayName, l.Email, l.Id, l.ProcessDate, l.StatusId, l.TicketDate, l.TicketNo, l.UserId, r.FlightNos });
                var ticketResult = sql.FirstOrDefault();
                if (ticketResult == null) return;
                lstResult.Items.Add(new ListViewItem(new string[] { 
                    (lstResult.Items.Count+1).ToString(),
                    TicketNo,
                    GetEnumName((DetrStatus)ticketResult.StatusId).Replace(@"[邮件通知状态]", string.Empty),
                    ticketResult.FlightNos == null ? string.Empty : @"[" + string.Join("][", ticketResult.FlightNos.Distinct().ToArray()) + @"]"
                }) );
            }
        }


        #region 辅助方法
        protected string GetEnumName(Enum value) //where T:enum
        {
            StringBuilder sb = new StringBuilder();
            FlagsAttribute attr = Attribute.GetCustomAttribute(value.GetType(), typeof(FlagsAttribute)) as FlagsAttribute;
            if (attr == null)
            {
                return GetDescription(value);
            }
            int t = (int)Convert.ChangeType(value, typeof(int));
            //Enum x = (Enum)Convert.ChangeType(value, typeof(Enum));
            Enum.GetValues(value.GetType()).Cast<Enum>().ToList().ForEach(l =>
            {
                Enum y = Convert.ChangeType(l, typeof(Enum)) as Enum;
                int x = (int)Convert.ChangeType(l, typeof(Enum));
                if ((t & x) != 0)
                {
                    string v = GetDescription(l);
                    if (!string.IsNullOrEmpty(v))
                        sb.AppendFormat(@"[{0}]", GetDescription(y));
                }
            });
            return sb.ToString();
        }
        /// <summary>
        /// 返回指定枚举值的描述（通过 
        /// <see cref="System.ComponentModel.DescriptionAttribute"/> 指定）。
        /// 如果没有指定描述，则返回枚举常数的名称，没有找到枚举常数则返回枚举值。
        /// </summary>
        /// <param name="value">要获取描述的枚举值。</param>
        /// <returns>指定枚举值的描述。</returns>
        protected string GetDescription(Enum value)
        {
            Type enumType = value.GetType();
            {
                MemberInfo[] mi = value.GetType().GetMember(value.ToString());
                if (mi != null && mi.Length > 0)
                {
                    DescriptionAttribute attr = Attribute.GetCustomAttribute(mi[0], typeof(DescriptionAttribute)) as DescriptionAttribute;
                    if (attr != null)
                    {
                        return attr.Description;
                    }
                }
            }
            return string.Empty;
        }


        #endregion


        private void RenderProgress(int? MaxValue, int? CurrentValue) {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new RenderProgressHandler(RenderProgress), MaxValue,CurrentValue);
                return;
            }
            else
            {
                if (MaxValue.HasValue) {
                    toolProgress.Maximum = MaxValue ?? 0;
                }
                if (CurrentValue.HasValue&& CurrentValue.Value<= toolProgress.Maximum && CurrentValue.Value>=0)
                    toolProgress.Value = CurrentValue??0;

                if(CurrentValue.HasValue && CurrentValue ==toolProgress.Maximum)
                    RendStrip(btnExportExcel, btnExportExcel.Text, true);
            }
        }

        private void RendStrip(ToolStripItem item, string text, bool? enable)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new RenderStatusHandler(RendStrip), item,text,enable);
                return;
            }
            else
            {
                item.Text = text;
                if (enable.HasValue)
                    item.Enabled = enable ?? false;
            }
        }

        private void ExecuteFile(Stream excel) {
            int Count = 0;
            new NPOIDetr(excel).ReadExcel(0).ForEach(l =>
            {
                ++Count;
                l.StatusId = (int)DetrStatus.PENDDING;
                l.Save();
                RenderTicketNo(l);
                RendStrip(toolMessage, string.Format(@"发现票号：{0}", l.TicketNo),null);
            });
            RenderProgress(Count, null);
            RendStrip(btnAction, btnAction.Text, true);
            excel.Dispose();
        }

        private void btnAction_Click(object sender, EventArgs e)
        {
            //lsvTicketNo.Items.Cast<ListViewItem>().ToList().ForEach(l => { 
            PlugIn.Execute();
            //new Thread(new ThreadStart(Dequene)).Start();
            //});
        }

        private void btnSetting_Click(object sender, EventArgs e)
        {
            new frmSetting().ShowDialog();
        }

        #region 导出Excel
        public MemoryStream ToExcel()
        {


            int rowIndex = 0;

            //创建workbook
            HSSFWorkbook workbook = new HSSFWorkbook();
            MemoryStream ms = new MemoryStream();
            ISheet sheet = workbook.CreateSheet("票号清单");
            IRow row = sheet.CreateRow(rowIndex);


            //表头样式
            ICellStyle style = workbook.CreateCellStyle();
            style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER;//居中对齐
            //表头单元格背景色
            style.FillForegroundColor = HSSFColor.SKY_BLUE.index;
            style.FillPattern = FillPatternType.SOLID_FOREGROUND;
            //表头单元格边框
            style.BorderTop = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            style.TopBorderColor = HSSFColor.BLACK.index;
            style.BorderRight = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            style.RightBorderColor = HSSFColor.BLACK.index;
            style.BorderBottom = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            style.BottomBorderColor = HSSFColor.BLACK.index;
            style.BorderLeft = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            style.LeftBorderColor = HSSFColor.BLACK.index;
            //表头字体设置
            IFont font = workbook.CreateFont();
            font.FontHeightInPoints = 12;//字号
            font.Boldweight = 600;//加粗
            font.Color = HSSFColor.WHITE.index;//颜色
            style.SetFont(font);

            //数据样式
            ICellStyle datastyle = workbook.CreateCellStyle();
            datastyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.LEFT;//左对齐
            //数据单元格的边框
            datastyle.BorderTop = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            datastyle.TopBorderColor = HSSFColor.BLACK.index;
            datastyle.BorderRight = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            datastyle.RightBorderColor = HSSFColor.BLACK.index;
            datastyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            datastyle.BottomBorderColor = HSSFColor.BLACK.index;
            datastyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.DOUBLE;
            datastyle.LeftBorderColor = HSSFColor.BLACK.index;
            //数据的字体
            IFont datafont = workbook.CreateFont();
            datafont.FontHeightInPoints = 11;//字号
            datastyle.SetFont(datafont);

            //设置列宽
            sheet.SetColumnWidth(0, 20 * 256);
            int colWidth0 = sheet.GetColumnWidth(0);

            sheet.SetColumnWidth(1, 60 * 256);
            int colWidth1 = sheet.GetColumnWidth(1);

            sheet.SetColumnWidth(2, 60 * 256);
            int colWidth2 = sheet.GetColumnWidth(2);

            //sheet.SetColumnWidth(3, 35 * 256);
            //int colWidth3 = sheet.GetColumnWidth(3);

            //sheet.SetColumnWidth(4, 20 * 256);
            //int colWidth4 = sheet.GetColumnWidth(4);

            //sheet.SetColumnWidth(5, 60 * 256);
            //int colWidth5 = sheet.GetColumnWidth(5);

            //设置行高
            sheet.DefaultRowHeight = 200 * 20;

            //表头数据
            ICell cell0 = row.CreateCell(0);
            cell0.SetCellValue("票号");
            cell0.CellStyle = style;

            ICell cell1 = row.CreateCell(1);
            cell1.SetCellValue("状态");
            cell1.CellStyle = style;

            ICell cell2 = row.CreateCell(2);
            cell2.SetCellValue("航班列表");
            cell2.CellStyle = style;

            //填充数据
            foreach (var fd in lstResult.Items.Cast<ListViewItem>())
            {
                rowIndex++;
                row = sheet.CreateRow(rowIndex);

                cell0 = row.CreateCell(0);
                cell0.SetCellValue(fd.SubItems[1].Text);
                cell0.CellStyle = datastyle;


                cell1 = row.CreateCell(1);
                cell1.SetCellValue(fd.SubItems[2].Text);
                cell1.CellStyle = datastyle;

                cell2 = row.CreateCell(2);
                cell2.SetCellValue(fd.SubItems[3].Text);
                cell2.CellStyle = datastyle;
            }

            workbook.Write(ms);
            ms.Flush();
            ms.Position = 0;

            workbook = null;
            sheet = null;
            row = null;

            return ms;
        }
        #endregion

        private void btnExportExcel_Click(object sender, EventArgs e)
        {
            if (saveFileDialog1.ShowDialog() == DialogResult.OK) {
                MemoryStream st = ToExcel();
                using (FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.CreateNew))
                {
                    BinaryWriter bw = new BinaryWriter(fs);
                    bw.Write(st.ToArray());
                }
                st.Dispose();
                MessageBox.Show(string.Format(@"文件已成功导出至 {0} ，请查看导出文件。",saveFileDialog1.FileName), @"票号库导出", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Application.Exit(new CancelEventArgs(false));
        }
    }
}
